#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include"shep_json.h"

using namespace std;

static int main_ret = 0;  //返回值  0: 正常  1: 异常
static int test_count = 0;//总测试数
static int test_pass = 0; //通过的测试数


//将 #define 改成 inline 函数后调试的时候不能显示行号，所以暂且用 #define
// template<typename T>
// inline void except_eq_base(bool equality, const T& expect, const T& actual){
//     test_count++;
//     if(equality){
//         test_pass++;
//     }
//     else{
//         cerr << __FILE__ << ":" << __LINE__ << ": expect: \" " << expect << " \" actual: \" " << actual
//              << " \"" << endl; 
//         main_ret = 1;
//     }
// }

#define EXPECT_EQ_BASE(equality, expect, actual, format)\
do{\
    test_count++;\
    if(equality)\
        test_pass++;\
    else{\
        fprintf(stderr, "%s:%d: expect: " format " actual: " format "\n", __FILE__, __LINE__, expect, actual);\
        main_ret = 1;\
    }\
}while(0)

#define EXPECT_EQ_INT(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%d")
#define EXPECT_EQ_DOUBLE(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%.17g")
#define EXPECT_TRUE(actual) EXPECT_EQ_BASE(actual, "true", "false", "%s")
#define EXPECT_FALSE(actual) EXPECT_EQ_BASE(!actual, "true", "false", "%s")
#define EXPECT_EQ_STRING(expect, actual, alength)\
    EXPECT_EQ_BASE(sizeof(expect) - 1 == alength && memcmp(expect, actual, alength) == 0, expect, actual, "%s")

static void test_parse_null(){
    shep_value v;
    v.set_type(SHEP_FALSE);
    EXPECT_EQ_INT(SHEP_PARSE_OK, shep_parse(v, "null"));
    EXPECT_EQ_INT(SHEP_NULL, v.get_type());
}

static void test_parse_true(){
    shep_value v;
    v.set_type(SHEP_FALSE);
    EXPECT_EQ_INT(SHEP_PARSE_OK, shep_parse(v, "true"));
    EXPECT_EQ_INT(SHEP_TRUE, v.get_type()); 
}

static void test_parse_false(){
    shep_value v;
    EXPECT_EQ_INT(SHEP_PARSE_OK, shep_parse(v, "false"));
    EXPECT_EQ_INT(SHEP_FALSE, v.get_type()); 
}

#define TEST_NUMBER(expect, json)\
    do{\
        shep_value v;\
        EXPECT_EQ_INT(SHEP_PARSE_OK, shep_parse(v, json));\
        EXPECT_EQ_INT(SHEP_NUMBER, v.get_type());\
        EXPECT_EQ_DOUBLE(expect, v.get_number());\
    } while(0)

static void test_parse_number() {
    TEST_NUMBER(0.0, "0");
    TEST_NUMBER(0.0, "-0");
    TEST_NUMBER(0.0, "-0.0");
    TEST_NUMBER(1.0, "1");
    TEST_NUMBER(-1.0, "-1");
    TEST_NUMBER(1.5, "1.5");
    TEST_NUMBER(-1.5, "-1.5");
    TEST_NUMBER(3.1416, "3.1416");
    TEST_NUMBER(1E10, "1E10");
    TEST_NUMBER(1e10, "1e10");
    TEST_NUMBER(1E+10, "1E+10");
    TEST_NUMBER(1E-10, "1E-10");
    TEST_NUMBER(-1E10, "-1E10");
    TEST_NUMBER(-1e10, "-1e10");
    TEST_NUMBER(-1E+10, "-1E+10");
    TEST_NUMBER(-1E-10, "-1E-10");
    TEST_NUMBER(1.234E+10, "1.234E+10");
    TEST_NUMBER(1.234E-10, "1.234E-10");
    TEST_NUMBER(0.0, "1e-10000"); /* must underflow */
    TEST_NUMBER(1.0000000000000002, "1.0000000000000002"); /* the smallest number > 1 */
    TEST_NUMBER( 4.9406564584124654e-324, "4.9406564584124654e-324"); /* minimum denormal */
    TEST_NUMBER(-4.9406564584124654e-324, "-4.9406564584124654e-324");
    TEST_NUMBER( 2.2250738585072009e-308, "2.2250738585072009e-308");  /* Max subnormal double */
    TEST_NUMBER(-2.2250738585072009e-308, "-2.2250738585072009e-308");
    TEST_NUMBER( 2.2250738585072014e-308, "2.2250738585072014e-308");  /* Min normal positive double */
    TEST_NUMBER(-2.2250738585072014e-308, "-2.2250738585072014e-308");
    TEST_NUMBER( 1.7976931348623157e+308, "1.7976931348623157e+308");  /* Max double */
    TEST_NUMBER(-1.7976931348623157e+308, "-1.7976931348623157e+308");
}

#define TEST_STRING(expect, json)\
    do{\
        shep_value v;\
        EXPECT_EQ_INT(SHEP_PARSE_OK, shep_parse(v, json));\
        EXPECT_EQ_INT(SHEP_STRING, v.get_type());\
        EXPECT_EQ_STRING(expect, v.get_string(), v.get_string_length());\
    }while(0)

static void test_parse_string(){
    TEST_STRING("", "\"\"");
    TEST_STRING("Hello", "\"Hello\"");

    TEST_STRING("Hello\nWorld", "\"Hello\\nWorld\"");
    TEST_STRING("\" \\ / \b \f \n \r \t", "\"\\\" \\\\ \\/ \\b \\f \\n \\r \\t\"");
}

#define TEST_ERROR(error, json)\
    do {\
        shep_value v;\
        v.set_type(SHEP_FALSE);\
        EXPECT_EQ_INT(error, shep_parse(v, json));\
        EXPECT_EQ_INT(SHEP_NULL, v.get_type());\
    } while(0)
    
static void test_parse_expect_value(){
    TEST_ERROR(SHEP_PARSE_EXCEPT_VALUE, "");
    TEST_ERROR(SHEP_PARSE_EXCEPT_VALUE, " ");
}

static void test_parse_invalid_value(){
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, "nul");
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, "?");

    /* invalid number */
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, "+0");
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, "+1");
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, ".123"); /* at least one digit before '.' */
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, "1.");   /* at least one digit after '.' */
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, "INF");
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, "inf");
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, "NAN");
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, "nan");
}

static void test_parse_root_not_singular(){
    TEST_ERROR(SHEP_PARSE_ROOT_NOT_SINGULAR, "null x");
    /* invalid number */
    TEST_ERROR(SHEP_PARSE_ROOT_NOT_SINGULAR, "0123"); /* after zero should be '.' , 'E' , 'e' or nothing */
    TEST_ERROR(SHEP_PARSE_ROOT_NOT_SINGULAR, "0x0");
    TEST_ERROR(SHEP_PARSE_ROOT_NOT_SINGULAR, "0x123");
}

static void test_parse_number_too_big(){
    TEST_ERROR(SHEP_PARSE_NUMBER_TOO_BIG, "1e309");
    TEST_ERROR(SHEP_PARSE_NUMBER_TOO_BIG, "-1e309");
}

static void test_parse_missing_quotation_mark(){
    TEST_ERROR(SHEP_PARSE_MISS_QUOTATION_MARK, "\"");
    TEST_ERROR(SHEP_PARSE_MISS_QUOTATION_MARK, "\"abc");
}

static void test_parse_invalid_string_escape() {
    TEST_ERROR(SHEP_PARSE_INVALID_STRING_ESCAPE, "\"\\v\"");
    TEST_ERROR(SHEP_PARSE_INVALID_STRING_ESCAPE, "\"\\'\"");
    TEST_ERROR(SHEP_PARSE_INVALID_STRING_ESCAPE, "\"\\0\"");
}

static void test_parse_invalid_string_char() {
    TEST_ERROR(SHEP_PARSE_INVALID_STRING_CHAR, "\"\x01\"");
    TEST_ERROR(SHEP_PARSE_INVALID_STRING_CHAR, "\"\x1F\"");
    TEST_ERROR(SHEP_PARSE_INVALID_STRING_ESCAPE, "\"\\x12\"");
}

static void test_access_null(){
    shep_value v;
    v.set_string("a", 1);
    v.set_null();
    EXPECT_EQ_INT(SHEP_NULL, v.get_type());
}

static void test_access_boolean(){
    shep_value v;
    v.set_null();
    v.set_boolean(true);
    EXPECT_TRUE(v.get_boolean());
    v.set_boolean(false);
    EXPECT_FALSE(v.get_boolean());
}

static void test_access_number(){
    shep_value v;
    v.set_null();
    v.set_number(123.0);
    EXPECT_EQ_INT(SHEP_NUMBER, v.get_type());
    EXPECT_EQ_DOUBLE(123.0, v.get_number());
}

static void test_access_string(){
    shep_value v;
    v.set_string("", 0);
    EXPECT_EQ_STRING("", v.get_string(), v.get_string_length());
    v.set_string("Hello", 5);
    EXPECT_EQ_STRING("Hello", v.get_string(), v.get_string_length());
}


static void test_parse() {
    test_parse_null();
    test_parse_true();
    test_parse_false();
    test_parse_number();
    test_parse_string();
    test_parse_expect_value();
    test_parse_invalid_value();
    test_parse_root_not_singular();
    test_parse_number_too_big();
    test_parse_missing_quotation_mark();
    test_parse_invalid_string_escape();
    test_parse_invalid_string_char();

    test_access_null();
    test_access_boolean();
    test_access_number();
    test_access_string();
}

int main(){
    test_parse();
    cout << test_pass << "/" << test_count << " (" << test_pass * 100.0 / test_count
    << ") passed." << endl;
    return main_ret;
}